﻿#ifndef TABLEMODEL_H
#define TABLEMODEL_H

#include <QtCore>
#include <QtQml>
#include<QDebug>
#include <QAbstractTableModel>
#include"invalidsearch.h"
#include"640search.h"

//↑ ↓ ← → ↖ ↗ ↙ ↘
class TableModel : public QAbstractTableModel
{
    Q_OBJECT

    Q_PROPERTY(int cols READ cols /*WRITE setcols*/ NOTIFY colsChanged)
    Q_PROPERTY(int rows READ rows /*WRITE setRows*/ NOTIFY rowsChanged)
signals:
//    void editMapChanged(int);
    void colsChanged(int);
    void rowsChanged(int);
public:
    Q_INVOKABLE void resetAll(int c=0,int r=0)
    {
        qDebug()<<"resetMap:";
        beginResetModel();
        reset(c,r);
        endResetModel();
//        emit dataChanged(index(0,0),index(cols()-1,rows()-1));
    }
    Q_INVOKABLE void cleanMap()
    {
        qDebug()<<"cleanMap:";
        reset(cols(),rows());
        emit dataChanged(index(0,0),index(rows()-1,cols()-1));
    }
    Q_INVOKABLE void resetSearch()
    {
        qDebug()<<"resetSearch:";
        clearSearch();
        map->clearData();
        emit dataChanged(index(0,0),index(rows()-1,cols()-1));
    }
    Q_INVOKABLE void stepSearch(int s=0,int d=0)
    {
        qDebug()<<"单步搜索:";
        initSearch(s,d);
        search->step();
    }
    Q_INVOKABLE void autoSearch(int s=0,int d=0)
    {
        qDebug()<<"autoSearch!";
        initSearch(s,d);
        search->Continuous();
    }
    void initSearch(int s=0,int d=0)
    {
        qDebug()<<"单步搜索:";
        if(search==nullptr){
            switch (s) {
            //["A*搜索","深度优先","宽度优先","贪婪搜索","等代价搜索"]
//            case 0:
//                break;
            case 1:
                search=new DFS(map);
                break;
            case 2:
                search=new BFS(map);
                break;
            default:
                search=new InvalidSearch(map);
                break;
            }
        }
        search->setDistance(d+1);
    }
    void reset(int c=0,int r=0){
        clearSearch();
        clearMap();
        if(c&&r){
            map=new Map(Point(c,r));
        }else{
            map=new Map;
        }
        connect(map,&Map::mapChanged,this,&TableModel::mapChanged);
        connect(map,&Map::map_output,this,&TableModel::map_output);
    }
    void clearMap(){
        if(map){
            delete map;
        }
        map=nullptr;
    }
    void clearSearch(){
        if(search){
            delete search;
        }
        search=nullptr;
    }
    TableModel(){
        map=nullptr;
        search=nullptr;
        reset();
    }
    ~TableModel(){
        delete map;
    }
    int cols() const
    {
        return map->X();
    }
    int rows() const
    {
        return map->Y();
    }
//    void setcols(int editMap)
//    {
//        m_editMap=editMap;
//        emit editMapChanged(editMap);
//    }
    enum Roles {
        ObjectRole = Qt::UserRole,
        X,
        Y,
        COLOR,
        STATE,
        TEXT,
        FLAG,
        PRE,
        OUTPUT,
    };

    int rowCount(const QModelIndex & = QModelIndex()) const override
    {
        return map->Y();
    }

    int columnCount(const QModelIndex & = QModelIndex()) const override
    {
        return map->X();
    }

    QVariant data(const QModelIndex &index, int role) const override
    {
        switch (role) {
            case Qt::DisplayRole:
                return QString("%1, %2").arg(index.column()).arg(index.row());
        case COLOR:
            return stateColor[map->is(p(index))];
        case STATE:
            return map->is(p(index));
        case X:
            return index.column();
        case Y:
            return index.row();
        case OUTPUT:
            return map->isOutput(p(index));
        case TEXT:
            return map->getText(p(index));
        case FLAG:
            return map->getFlag(p(index));
        case PRE:
            return map->getPreInt(p(index));
        default:
                break;

        }

        return QVariant();
    }
    void mapChanged(Point p)
    {
        auto i=index(p.y,p.x);
        emit dataChanged(i,i,{STATE,COLOR});
        qDebug()<<"SLOT(mapChanged(Point))";
    }
    void map_output(Point p)
    {
        auto i=index(p.y,p.x);
        emit dataChanged(i,i,{/*STATE,COLOR,*/OUTPUT,TEXT,PRE,FLAG});
        qDebug()<<"SLOT(map_output(Point))";
    }
    bool setData(const QModelIndex &index, const QVariant &value, int role=STATE) override
    {
        if(index.column()>=map->X()||index.row()>=map->Y()){
            return false;
        }
        switch (role) {
        case STATE:
            map->set(p(index),value.toInt());
            //emit dataChanged(index,index,{STATE,COLOR});//
            qDebug()<<index<<"data"<<index.column()<<","<<index.row()<<"set"<<value;
            return true;
        default:
                return false;

        }
    }
//    Q_INVOKABLE bool setDataByRowColumn(int row, int column, const QVariant &data)
//    {
//        auto i=index(column,row);
//        qDebug()<<i<<"setDataByRowColumn"<<data;
//        return setData( i, data);
//    }
//    Q_INVOKABLE bool testData()
//    {
//        return setDataByRowColumn(0,1,2);
//    }
protected:
    QHash<int, QByteArray> roleNames() const override
    {
        return { {Qt::DisplayRole, "display"},{COLOR, "color1"},{X,"X"},{Y,"Y"},{STATE,"state"},{OUTPUT,"output"},{TEXT,"text"},{FLAG,"flag"},{PRE,"pre"} };
    }
private:
    Point p(const QModelIndex &index)const {
        Point p(index.column(), index.row());
        return p;
    }
    QHash<int,QString>stateColor={{CLEAR,"#FFFFFF"},{BLOCK,"#7F7F7F"},{START,"#00EE00"},{END,"#FF6347"},{OPEN,"#AFEEEE"},{CLOSED,"#98FB98"},{PATH,"#E3FC53"}};
    Map*map;
    VirtualSearch*search;
};

#endif // TABLEMODEL_H
